/**
 *   树形打印对象，以及相关容器
 *   Created by wileywang@2012-07-09
 */
#ifndef PPRINT_HEADER_WILEYWANG
#define PPRINT_HEADER_WILEYWANG
 
 
#include <unistd.h>
#include <stdint.h>
#include <ostream>
#include <vector>
#include <map>
#include <string>
#include <sstream>
#include <bitset>
#include <list>
#include <set>

#define NEW_LINE  "\r\n"

template<class T>
struct pp_type
{
	static const uint8_t type = 0;
};

template<>
struct pp_type<uint8_t>
{
	static const uint8_t type = 5;
};

template<>
struct pp_type<uint16_t>
{
	static const uint8_t type = 1;
};

template<>
struct pp_type<uint32_t>
{
	static const uint8_t type = 1;
};

template<>
struct pp_type<uint64_t>
{
	static const uint8_t type = 1;
};

template<>
struct pp_type<int8_t>
{
	static const uint8_t type = 5;
};

template<>
struct pp_type<int16_t>
{
	static const uint8_t type = 1;
};

template<>
struct pp_type<int32_t>
{
	static const uint8_t type = 1;
};

template<>
struct pp_type<int64_t>
{
	static const uint8_t type = 1;
};

template<>
struct pp_type<std::string>
{
	static const uint8_t type = 2;
};

template<>
struct pp_type<char *>
{
	static const uint8_t type = 2;
};

template<>
struct pp_type<const char*>
{	
	static const uint8_t type = 2;
};

template<class T>
struct pp_type<T*>
{
	static const uint8_t type = 3;
};

template<class T>
struct pp_type<const T*>
{
	static const uint8_t type = 3;
}; 

template<>
struct pp_type<bool>
{
	static const uint8_t type = 4;
};


#define g_printIdent(os, ident) \
	for(int indexIdent = 0; indexIdent < ident; ++indexIdent) \
	{ \
		os << "  "; \
	} 

/*
 *  默认打印对象类型
 */
template<uint8_t Type>
class PPrintTemplate
{
public:
	template<class Value>
	static void pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident, bool bNewLine = true)
	{
		g_printIdent(os, ident);
		if(valueName.length())
		{
			os << valueName << " : ";
		}

		os << "{" << NEW_LINE;
		++ident;
		pValue.DumpDataTree(os, ident);
		--ident;
		g_printIdent(os, ident);
		os << "}";

		if(bNewLine)
		{
			os << NEW_LINE;
		}
	}
};

/*
 * 打印基本类型
 */
template<> 
class PPrintTemplate<1>
{
public:
	template<class Value>
	static void pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident, bool bNewLine = true)
	{
		g_printIdent(os, ident);
		if(valueName.length()){
			os << valueName << " : ";
		}

		os << pValue;

		if(bNewLine)
		{
			os << NEW_LINE;
		}
	}
};

/*
 *	打印字符串类型
 */
template<>
class PPrintTemplate<2>
{
public:
	template<class Value>
	static void pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident, bool bNewLine = true)
	{
		g_printIdent(os, ident);
		if(valueName.length()){
			os << valueName << " : ";
		}

		os << '"' << pValue << '"';

		if(bNewLine)
		{
			os << NEW_LINE;
		}
	}
};

/*
 *  打印指针类型
 */
template<>
class PPrintTemplate<3>
{
public:
	template<class Value>
	static void pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident, bool bNewLine = true)
	{
		g_printIdent(os, ident);
		if(valueName.length()){
			os << valueName << "[P] : ";
		}

		//PPrintTemplate<pp_type<remove_pointer<Value>::type>::type>(os, "", *pValue, ident, false);
		os << std::hex << "0x" << (int64_t) pValue ;

		if(bNewLine)
		{
			os << NEW_LINE;
		}
	}
};

/*
 *  打印bool类型
 */
template<>
class PPrintTemplate<4>
{
public:
	template<class Value>
	static void pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident, bool bNewLine = true)
	{
		g_printIdent(os, ident);
		if(valueName.length()){
			os << valueName << ": ";
		}
	
		if(pValue)
		{
			os << "true";
		}
		else
		{
			os << "false";
		}

		if(bNewLine)
		{
			os << NEW_LINE;
		}
	}
};

// 蛋疼的uint_8和int_8居然不打印,专门用这个类型解决打印问题
template<>
class PPrintTemplate<5>
{
public:
	template<class Value>
	static void pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident, bool bNewLine = true)
	{
		g_printIdent(os, ident);
		if(valueName.length()){
			os << valueName << ": ";
		}
	
		os << (int)pValue;

		if(bNewLine)
		{
			os << NEW_LINE;
		}
	}
};

template<class Value>
void g_pprint(std::ostream& os, const std::string& valueName, const Value& pValue, int ident)
{
	PPrintTemplate<pp_type<Value>::type>::pprint(os, valueName, pValue, ident);
}

template<size_t N>
void g_pprint(std::ostream& os, const std::string& valueName, const std::bitset<N>& pBits, int ident)
{
	g_printIdent(os, ident);
	os << valueName << " : {" ;
	
	++ident;
	for(int index = 0; index < (int)N; ++index)
	{
		if(0 == index % 16 )
		{
			os << NEW_LINE;
			g_printIdent(os, ident);
		}
		if(pBits[index])
		{
			os << "1";
		}
		else
		{
			os << "0";
		}
	}
	os << NEW_LINE;
	--ident;
	
	g_printIdent(os, ident);
	os << "}" << NEW_LINE;
}

/**
 *  应该可以使用更加复杂的模版泛型递推，目前先利用重复代码简便处理
 */
template<class Value>
void g_pprint(std::ostream& os, const std::string& valueName, const std::vector<Value>& oVec, int ident)
{
	g_printIdent(os, ident);
	os << valueName << " : {" << NEW_LINE;
	
	int index = 0;
	for(typename std::vector<Value>::const_iterator vecIt = oVec.begin();
			vecIt != oVec.end(); ++vecIt, ++index)
	{
		std::stringstream indexStream;
		indexStream << "[" << index << "]";
		++ident;
		g_pprint(os, indexStream.str(), *vecIt, ident);
		--ident;
	}
	g_printIdent(os, ident);
	os << "}" << NEW_LINE;
}

template<class Value>
void g_pprint(std::ostream& os, const std::string& valueName, const std::list<Value>& oVec, int ident)
{
	g_printIdent(os, ident);
	os << valueName << " : {" << NEW_LINE;
	
	int index = 0;
	for(typename std::list<Value>::const_iterator listIt = oVec.begin();
			listIt != oVec.end(); ++listIt, ++index)
	{
		std::stringstream indexStream;
		indexStream << "[" << index << "]";
		++ident;
		g_pprint(os, indexStream.str(), *listIt, ident);
		--ident;
	}
	
	g_printIdent(os, ident);
	os << "}" << NEW_LINE;
}

template<class Key, class Value>
void g_pprint(std::ostream& os, const std::string& valueName, const std::map<Key, Value>& oMap, int ident)
{
	g_printIdent(os, ident);
	os << valueName << " : {" << NEW_LINE;
	
	for(typename std::map<Key, Value>::const_iterator mapIt = oMap.begin();
			mapIt != oMap.end(); ++mapIt)
	{
		std::stringstream keyStream;
		PPrintTemplate<pp_type<Key>::type>::pprint(keyStream, "", mapIt->first, 0, false);
		++ident;
		g_pprint(os, keyStream.str(), mapIt->second, ident);
		--ident;
	}
	g_printIdent(os, ident);
	os << "}" << NEW_LINE;
}

template<class Key, class Value>
void g_pprint(std::ostream& os, const std::string& valueName, const std::multimap<Key, Value>& oMap, int ident)
{
	g_printIdent(os, ident);
	os << valueName << " : {" << NEW_LINE;
	
	for(typename std::multimap<Key, Value>::const_iterator mapIt = oMap.begin();
			mapIt != oMap.end(); ++mapIt)
	{
		std::stringstream keyStream;
		PPrintTemplate<pp_type<Key>::type>::pprint(keyStream, "", mapIt->first, 0, false);
		++ident;
		g_pprint(os, keyStream.str(), mapIt->second, ident);
		--ident;
	}
	
	g_printIdent(os, ident);
	os << "}" << NEW_LINE;
}

template<class Key>
void g_pprint(std::ostream& os, const std::string& valueName, const std::set<Key>& oSet, int ident)
{
	g_printIdent(os, ident);
	os << valueName << " : {" << NEW_LINE;
	
	int index = 0;
	for(typename std::set<Key>::const_iterator setIt = oSet.begin();
			setIt != oSet.end(); ++setIt, ++index)
	{
		std::stringstream indexStream;
		indexStream << "[" << index << "]";
		++ident;
		g_pprint(os, indexStream.str(), *setIt, ident);
		--ident;
	}
	
	g_printIdent(os, ident);
	os << "}" << NEW_LINE;
}

#endif
